#ifndef __SUBSYSTEM_PLAYERS_H__
#define __SUBSYSTEM_PLAYERS_H__

#include <vector>
#include <map>
#include <list>
#include <mutex>

#include "blockingconcurrentqueue.h"
#include "Subsystem.hpp"
#include "entt/entt.hpp"
#include "GameType.h"
#include "GameLock.hpp"

#include "Engine/GameGuid.h"

using namespace PocketSurvival::Engine;

namespace PocketSurvival
{

    struct PlayerGroup
    {
        std::list<GameGuid> playerList;
        std::string groupName;
    };

    class SubsystemPlayers : public Subsystem
    {
    public:
        SubsystemPlayers();

        virtual void onEntityAdded(entt::entity entity) override;
        virtual void onEntityRemoved(entt::entity entity) override;

        virtual void update(float dt) override;
        virtual void load(const nlohmann::json& json) override;
        virtual void save(nlohmann::json& json) override;
        virtual void saveToMsgJson(nlohmann::json &jsonData) override;

        virtual const std::string& getName() const override;
        virtual SubUpdateType getUpdateType() override;

    public:

        void addPlayer(PlayerDataPtr &playerData);
        void removePlayer(PlayerDataPtr &playerData);
        void savePlayer(PlayerDataPtr &playerData);

        void getAllPlayerData(std::vector<PlayerDataPtr> &playerDataVec);
        void getPlayerDataByName(const std::string &username, std::vector<PlayerDataPtr> &playerDataVec);
        PlayerDataPtr getPlayerDataByGuid(const GameGuid &guid);

        bool playerGuidGetName(const GameGuid &guid, std::string& outName);

    protected:

        void playerDataSetID(PlayerDataPtr &playerData);
        void playerDataRecycleID(PlayerDataPtr &playerData);


    public:
        bool createGroup(PlayerDataPtr &playerData, const std::string &groupName);
        bool exitGroup(PlayerDataPtr &playerData);
        bool joinGroup(PlayerDataPtr &playerData, const GameGuid& groupKey);
        bool haveGroup(const GameGuid& groupKey);

    protected:
        std::map<int32_t, PlayerDataPtr> m_playerDataMap;
        SpinLock m_playerDataMapLock;

        moodycamel::BlockingConcurrentQueue<PlayerDataPtr> m_addPlayerQueue;
        moodycamel::BlockingConcurrentQueue<PlayerDataPtr> m_removePlayerQueue;

        // 玩家群组
        std::map<GameGuid, PlayerGroup> m_playerGroups;
        std::recursive_mutex m_groupMutex;

        std::map<GameGuid, std::string> m_playerGuidNameMap;
        SpinLock m_playerGuidNameMapLock;
    };

    inline SubsystemPlayers::SubsystemPlayers() {}
}

#endif